using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

using OR.Reuse.Persistence;

using OR.Lazarus.Config;

namespace OR.Lazarus.Business
{
	public class CompilerEngine< SOURCE, COMPILED, VALIDATOR, COMPILER, GENERATOR > : OR.Lazarus.Business.ICompilerEngine
		where SOURCE : IProject, new()
		where COMPILED : IProject, new()
		where VALIDATOR : IProjectValidator< SOURCE >, new()
		where COMPILER : CompilerBase< SOURCE, COMPILED, VALIDATOR >, new()
		where GENERATOR : CodeGenerator< COMPILED >, new()
   {
      protected COMPILER mSourceCompiler;
		protected GENERATOR mCodeGenerator;

		protected event FileLoadEventHandler					mFileLoaded;
		protected event SourceCompileStartEventHandler		mSourceCompileStarted;
		protected event SourceCompileCompleteEventHandler	mSourceCompileCompleted;
		protected event GenerateEventHandler					mFileGenerated;
		protected event GenerateCompleteEventHandler			mGenerationCompleted;
		protected event TierGenerateEventHandler				mBeforeGenerateTier;
		protected event TierGenerateEventHandler				mAfterGenerateTier;
      protected event CompileEventHandler						mCompiledModelGenerated;
		protected event EventHandler								mBeforeGenerateCompiled;
		protected event EventHandler								mAfterGenerateCompiled;
		protected event EventHandler 								mBeforeGenerateManifest;
		protected event EventHandler 								mAfterGenerateManifest;
		
		public void Initialize()
		{
			mSourceCompiler = new COMPILER();
			mCodeGenerator = new GENERATOR();
		}

		public void Initialize( string pConfigPath, string pSourcePath )
		{
			this.Initialize();

			this.LoadConfig( pConfigPath );
			this.LoadSource( pSourcePath );
		}

		public void LoadConfig( string pFullPath )
		{
			XmlDocument vConfigFile = new XmlDocument();

         if ( DataUtility.IsEmpty( pFullPath ) || !File.Exists( pFullPath ) )
         {
            throw new ApplicationException( String.Format( "CompilerEngine.LoadConfig() failed: The file path [{0}] is invalid.", pFullPath ) );
         }

         vConfigFile.Load( pFullPath );

			mCodeGenerator.Config.LoadXml( vConfigFile.DocumentElement );

			this.OnFileLoaded( new FileLoadEventArgs( "Config", pFullPath, mCodeGenerator.Config.Length ) );
		}

		public void LoadSource( string pFullPath )
		{
			XmlDocument vSourceFile = new XmlDocument();

         if ( DataUtility.IsEmpty( pFullPath ) || !File.Exists( pFullPath ) )
         {
            throw new ApplicationException( String.Format( "CompilerEngine.LoadSource() failed: The file path [{0}] is invalid.", pFullPath ) );
         }

         vSourceFile.Load( pFullPath );

			mSourceCompiler.SourceProject.LoadXml( vSourceFile.DocumentElement );

			EventArgs vArgs = new EventArgs();

			this.OnFileLoaded( new FileLoadEventArgs( "Source", pFullPath, mSourceCompiler.SourceProject.Length ) );
		}

		public void Compile()
		{
			long mSourceLength = mSourceCompiler.SourceProject.Length;

			this.OnSourceCompileStarted( new SourceCompileStartEventArgs( mSourceLength ) );

			mSourceCompiler.Compile();
         
			this.OnSourceCompileCompleted( new SourceCompileCompleteEventArgs( mSourceLength, mSourceCompiler.CompiledProject.Length ) );

			mCodeGenerator.Compiled = mSourceCompiler.CompiledProject;

			mCodeGenerator.Initialize();

			mCodeGenerator.FilesToGenerate = mCodeGenerator.GetGenerateCount();
			mCodeGenerator.FilesGenerated = 0;

			//mCodeGenerator.GenerateFile += new GenerateEventHandler( this.DoGenerateFile );
			//mCodeGenerator.BeforeGenerateTier += new TierGenerateEventHandler( this.DoBeforeGenerateTier );
			//mCodeGenerator.AfterGenerateTier += new TierGenerateEventHandler( this.DoAfterGenerateTier );
			//mCodeGenerator.BeforeGenerateCompiled += new EventHandler( this.DoBeforeGenerateCompiled );
			//mCodeGenerator.AfterGenerateCompiled += new EventHandler( this.DoAfterGenerateCompiled );
			//mCodeGenerator.BeforeGenerateManifest += new EventHandler( this.DoBeforeGenerateManifest );
			//mCodeGenerator.AfterGenerateManifest += new EventHandler( this.DoAfterGenerateManifest );
			//mCodeGenerator.CompiledModelGenerated += new CompileEventHandler( this.DoCompiledModelGenerated );
			mCodeGenerator.Generate();

			this.OnGenerationCompleted( new GenerateCompleteEventArgs( mSourceLength, mCodeGenerator.Manifest.SumFileSize() ) );
		}

		#region Protected Event Handlers
      protected virtual void OnCompiledModelGenerated( CompileEventArgs e )
      {
         if ( mCompiledModelGenerated != null )
         {
            this.mCompiledModelGenerated( this, e );
         }

			LazarusConfig.LogViewerManager.AddCompileFileGenerated( e.Filename, e.FileSize );
      }

		protected virtual void OnFileLoaded( FileLoadEventArgs e )
		{
			if ( mFileLoaded != null )
			{
				this.mFileLoaded( this, e );
			}

			LazarusConfig.LogViewerManager.AddFileLoadLog( e );
		}

		protected virtual void OnSourceCompileStarted( SourceCompileStartEventArgs e )
		{
			if ( mSourceCompileStarted != null )
			{
				this.mSourceCompileStarted( this, e );
			}

			LazarusConfig.LogViewerManager.AddSourceCompilerStarted( e );
		}

		protected virtual void OnSourceCompileCompleted( SourceCompileCompleteEventArgs e )
		{
			if ( mSourceCompileCompleted != null )
			{
				this.mSourceCompileCompleted( this, e );
			}

			LazarusConfig.LogViewerManager.AddSourceCompilerCompleted( e );
		}

		protected virtual void OnFileGenerated( GenerateEventArgs e )
		{
			if ( mFileGenerated != null )
			{
				this.mFileGenerated( this, e );
			}

			LazarusConfig.LogViewerManager.AddGenerationLog( e );
		}

		protected virtual void OnGenerationCompleted( GenerateCompleteEventArgs e )
		{
			if ( mGenerationCompleted != null )
			{
				this.mGenerationCompleted( this, e );
			}

			LazarusConfig.LogViewerManager.AddGenerateCompleted( e );
		}

		protected virtual void OnBeforeGenerateTier( TierGenerateEventArgs e )
		{
			if ( mBeforeGenerateTier != null )
			{
				mBeforeGenerateTier( this, e );
			}
		}

		protected virtual void OnAfterGenerateTier( TierGenerateEventArgs e )
		{
			if ( mAfterGenerateTier != null )
			{
				mAfterGenerateTier( this, e );
			}
		}

		protected virtual void OnBeforeGenerateCompiled( EventArgs e )
		{
			if ( mBeforeGenerateCompiled != null )
			{
				mBeforeGenerateCompiled( this, e );
			}
		}

		protected virtual void OnAfterGenerateCompiled( EventArgs e )
		{
			if ( mAfterGenerateCompiled != null )
			{
				mAfterGenerateCompiled( this, e );
			}
		}

		protected virtual void OnBeforeGenerateManifest( EventArgs e )
		{
			if ( mBeforeGenerateManifest != null )
			{
				mBeforeGenerateManifest( this, e );
			}
		}

		protected virtual void OnAfterGenerateManifest( EventArgs e )
		{
			if ( mAfterGenerateManifest != null )
			{
				mAfterGenerateManifest( this, e );
			}
		}
		#endregion

		#region Public Events
      public event CompileEventHandler CompiledModelGenerated
      {
         add
         {
            mCompiledModelGenerated += value;
         }
         remove
         {
            mCompiledModelGenerated -= value;
         }
      }

		public event FileLoadEventHandler FileLoaded
		{
			add
			{
				mFileLoaded += value;
			}
			remove
			{
				mFileLoaded -= value;
			}
		}

		public event SourceCompileStartEventHandler SourceCompileStarted
		{
			add
			{
				mSourceCompileStarted += value;
			}
			remove
			{
				mSourceCompileStarted -= value;
			}
		}

		public event SourceCompileCompleteEventHandler SourceCompileCompleted
		{
			add
			{
				mSourceCompileCompleted += value;
			}
			remove
			{
				mSourceCompileCompleted -= value;
			}
		}

		public event GenerateEventHandler FileGenerated
		{
			add
			{
				mFileGenerated += value;
			}
			remove
			{
				mFileGenerated -= value;
			}
		}

		public event GenerateCompleteEventHandler GenerationCompleted
		{
			add
			{
				mGenerationCompleted += value;
			}
			remove
			{
				mGenerationCompleted -= value;
			}
		}
		#endregion

		#region Public Properties
      public COMPILER SourceCompiler
		{
			get
			{
				return ( mSourceCompiler );
			}
			set
			{
				mSourceCompiler = value;
			}
		}

		public GENERATOR CodeGenerator
		{
			get
			{
				return ( mCodeGenerator );
			}
			set
			{
				mCodeGenerator = value;
			}
		}

		public int FilesToGenerate
		{
			get
			{
				return ( mCodeGenerator.FilesToGenerate );
			}
		}

		public int FilesGenerated
		{
			get
			{
				return ( mCodeGenerator.FilesGenerated );
			}
		}

		public event EventHandler BeforeGenerateCompiled
		{
			add
			{
				mBeforeGenerateCompiled += value;
			}
			remove
			{
				mBeforeGenerateCompiled -= value;
			}
		}

		public event EventHandler AfterGenerateCompiled
		{
			add
			{
				mAfterGenerateCompiled += value;
			}
			remove
			{
				mAfterGenerateCompiled -= value;
			}
		}

		public event EventHandler BeforeGenerateManifest
		{
			add
			{
				mBeforeGenerateManifest += value;
			}
			remove
			{
				mBeforeGenerateManifest -= value;
			}
		}

		public event EventHandler AfterGenerateManifest
		{
			add
			{
				mAfterGenerateManifest += value;
			}
			remove
			{
				mAfterGenerateManifest -= value;
			}
		}

		public event TierGenerateEventHandler BeforeGenerateTier
		{
			add
			{
				mBeforeGenerateTier += value;
			}
			remove
			{
				mBeforeGenerateTier -= value;
			}
		}

		public event TierGenerateEventHandler AfterGenerateTier
		{
			add
			{
				mAfterGenerateTier += value;
			}
			remove
			{
				mAfterGenerateTier -= value;
			}
		}
		#endregion
	}
}
